#include <vector>
#include <queue>
#include "sched_rr2.h"
#include "basesched.h"
#include <iostream>
#include <utility>
#include <fstream>

using namespace std;

SchedRR2::SchedRR2(vector<int> argn) {
	// Round robin recibe la cantidad de cores y sus cpu_quantum por parámetro
	cores = argn[0];
	cout<<"cores: " <<cores<<endl;
	for(int i = 0; i < cores; i++ ){
		quantum.push_back(argn[i+1]);
		cout<<"cpu: " <<i<< " - quantum: " <<argn[i+1]<<endl;
		quantum_left.push_back(argn[i+1]);
		queue<int> queue;
		tareasCPU.push_back(queue);
	}
  
	//PARA ANALISIS
	vector<int> t(5);
	
	for(int i = 0; i < cores; i++ ){
		
		t.push_back(0);
	}
	
	for(int i = 0; i < 5; i++ ){
		
		ready_tarea_cpu.push_back(0);
	}
	
	for(int i = 0; i < cores; i++ ){
		vector<int> temp = t;
		Cont_cpu_tarea.push_back(temp);
	}
	for(int i = 0; i < cores; i++ ){
		current_tick_by_cpu.push_back(0);
	}
	//

}

SchedRR2::~SchedRR2() {
	//PARA ANALISIS
	//~ std::ofstream ss;

	
	std::ofstream myfile;
	std::ofstream myfile2;
	myfile2.open("RR_ecuanimidad.txt",ios_base::app);
	myfile.open("RR_Promedio.txt",ios_base::app);
	for(int i = 0; i < cores; i++){
	
		myfile2 << "CPU " << i <<" - " << " quantum:" << quantum[i] << ": ";
		myfile2 << Cont_cpu_tarea[i][0] <<" " << Cont_cpu_tarea[i][1] << " " << Cont_cpu_tarea[i][2] << " " << Cont_cpu_tarea[i][3] << " " << Cont_cpu_tarea[i][4] << " " << endl;
		
	}
	//~ myfile<< endl;
	myfile <<"Tiempo Ejec con Q:" << quantum[0] << ": ";
	for(int j=0; j< 5; j++){
		
		myfile<< ready_tarea_cpu[j] << " ";
		
	}
	myfile<< endl;
	
	

	//~ cout <<"Cerrando logs" <<endl;
	myfile2.close();
	myfile.close();
	//
}

//Devuelve la cantidad de tareas activas de una cpu ((RUNNING + BLOCKED + READY))
int SchedRR2::tareasActivas(std::vector<std::pair <int,int> > cpuXTarea, int cpu){
	int cantActivas = 0;
	for(unsigned int i = 0; i < cpuXTarea.size(); i++){
		if(cpuXTarea[i].second == cpu) cantActivas++;
	}
	
	return cantActivas;
}


//minCPU devuelve la cpu con menos tareas activas(RUNNING + BLOCKED + READY)
int SchedRR2::minCpu(){
    int min=tareasActivas(cpuXtareas, 0);
    int indiceMin=0; 	
        for(unsigned int i=0;i<cores; i++){
            
            if(tareasActivas(cpuXtareas, i) < min || (min == tareasActivas(cpuXtareas, i) &&current_pid(i)==IDLE_TASK) ){ 
            	min = tareasActivas(cpuXtareas, i);
            	indiceMin=i;
            }
        }

    return indiceMin;
}


void SchedRR2::load(int pid) {
	//busca la cpu menos cargada
	int min=minCpu();
    tareasCPU[min].push(pid);
    
    std::pair <int,int> cpuXtarea (pid, min);  
    cpuXtareas.push_back(cpuXtarea);
    cout<<"load tarea " <<pid;
	cout<<"en el cpu " << min <<endl;
}

int SchedRR2::getCpu(vector<pair <int,int> > cpuXTarea, int pid){
	int cpu = -1;
	for(unsigned int i = 0; i < cpuXTarea.size(); i++){
			if(cpuXTarea[i].first == pid){
					cpu = cpuXTarea[i].second;
					break;
			}
	}
	return cpu;
}

void SchedRR2::unblock(int pid) {
	
	int cpu=getCpu(cpuXtareas, pid);
	cout<<"tarea " <<pid;
	cout<<"en el cpu " << cpu <<endl;
	tareasCPU[cpu].push(pid);
}

int SchedRR2::tick(int cpu, const enum Motivo m) {
	
	current_tick_by_cpu[cpu] ++;	//ANALISIS
	
	if(m == TICK && (current_pid(cpu)!=IDLE_TASK)){
   
		//ANALISIS
		//cuando la tarea hace tick por primera vez
			if(ready_tarea_cpu[current_pid(cpu)]==0){
					ready_tarea_cpu[current_pid(cpu)] = current_tick_by_cpu[cpu];
			}
			
			//suma la vez q le toco CPU
			if(quantum[cpu] == quantum_left[cpu]){
					Cont_cpu_tarea[cpu][current_pid(cpu)]++;
			}
		//	

   
		//resto 1 al quantum_left[cpu]
		quantum_left[cpu]--; 
		//si no queda quantum, restauro el quantum y pido la proxima tarea --> next()
		if(quantum_left[cpu] == 0){
			tareasCPU[cpu].push(current_pid(cpu));
			return next(cpu);
		}else {
			return current_pid(cpu);
		}
	}
	// Si es BLOCK o EXIT, solo pido next()
	if(m == EXIT){// la saco de cpuXtarea para no contarla cuando cuento activas(le pongo como cpu -1)
		for(unsigned int i = 0; i < cpuXtareas.size(); i++){
			if(cpuXtareas[i].first == current_pid(cpu)) cpuXtareas[i].second = -1;
		}
	}
  
	//ANALISIS
	if(m==EXIT && (current_pid(cpu)!=IDLE_TASK)){
		//guardo tiempo de ejecucion = tiempo fin - tiempo inicio
		ready_tarea_cpu[current_pid(cpu)] = current_tick_by_cpu[cpu] - ready_tarea_cpu[current_pid(cpu)]  ;
		}
	//

	return next(cpu);
}

int SchedRR2::next(int cpu) {
	
		if(tareasCPU[cpu].empty()){
			quantum_left[cpu] = quantum[cpu];
			return IDLE_TASK;
		}else {
			int next_task = tareasCPU[cpu].front();
			tareasCPU[cpu].pop();
			quantum_left[cpu] = quantum[cpu];
			return next_task;
		}
}
